/***************************************************************************
 *   Copyright (C) 2007 by Warren Kenny   *
 *   warren.kenny@gmail.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include <otaClientCommand.h>
#include <otaMySQLCommonHeader.h>

otaClientCommand::otaClientCommand()
: m_commandType( OTA_CLIENT_COMMAND_IRRELEVANT ),
  m_rows( 0 ),
  m_fields( 0 ),
  m_responsePacketCount( 0 ),
  m_responseByteCount( 0 ),
  m_errNo( 0 ),
  m_autoIncrement( 0 )
{
	
}

bool otaClientCommand::deserialize( const otaTime arrivalTime, const char *data, unsigned int dataSize, const unsigned int offset, unsigned int &newOffset )
{
	otaMySQLCommonHeader header;
	bool ok = (	header.deserialize( data, dataSize, offset, newOffset ) &&
			otaBytePacker::removeBasicType( data, dataSize, newOffset, newOffset, m_commandType ) );
	if( ok )
	{
		std::cout << "received client command" << std::endl;
		m_start = arrivalTime;
		m_commandByteCount = ( dataSize );
		m_commandPacketCount = 1;
		switch( m_commandType )
		{
			case OTA_CLIENT_COMMAND_QUIT:            				// mysql_close
				m_commandString = "Client Quit";
			break;
			
			case OTA_CLIENT_COMMAND_INIT_DB:		         		// mysql_select_db 
			{
				std::string database;
				ok = otaBytePacker::removeNTString( data, dataSize, newOffset, newOffset, database );
				m_commandString = "Client attempted to select database " + database;
			}
			break;
			
			case OTA_CLIENT_COMMAND_QUERY:           				// mysql_real_query
				ok = otaBytePacker::removeNTString( data, dataSize, newOffset, newOffset, m_commandString );
			break;
			
			case OTA_CLIENT_COMMAND_FIELD_LIST:      				// mysql_list_fields
			{
				std::string table;
				ok = otaBytePacker::removeNTString( data, dataSize, newOffset, newOffset, table );
				m_commandString = "Client requested a field list from table " + table;
			}
			break;
			
			case OTA_CLIENT_COMMAND_CREATE_DB:      				// mysql_create_db (deprecated)
			{
				std::string database;
				ok = otaBytePacker::removeNTString( data, dataSize, newOffset, newOffset, database );
				m_commandString = "Client attempted to create database " + database;
			}
			break;	
			
			case OTA_CLIENT_COMMAND_DROP_DB:         				// mysql_drop_db (deprecated)
			{
				std::string database;
				ok = otaBytePacker::removeNTString( data, dataSize, newOffset, newOffset, database );
				m_commandString = "Client attempted to drop database " + database;
			}
			break;
					
			case OTA_CLIENT_COMMAND_SHUTDOWN:        				// mysql_shutdown
				m_commandString = "Client requested that the MySQL server shut down";
			break;
					
			case OTA_CLIENT_COMMAND_STATISTICS:     				// mysql_stat
				m_commandString = "Client requested a server status update";
			break;
					
			case OTA_CLIENT_COMMAND_PROCESS_INFO:    				// mysql_list_processes
				m_commandString = "Client requested a report on the status of all running threads";
			break;
					
			case OTA_CLIENT_COMMAND_PROCESS_KILL:    				// mysql_kill
			{
				unsigned int thread;
				ok = otaBytePacker::removeBasicType( data, dataSize, newOffset, newOffset, thread );
				m_commandString = "Client attempted to kill thread " + thread;	
			}
			break;
					
			case OTA_CLIENT_COMMAND_CHANGE_USER:     				// mysql_change_user
			{
				std::string username, scrambleBuffer, database;
				bool databaseSelected = false;
				ok = ( 		otaBytePacker::removeNTString( data, dataSize, newOffset, newOffset, username ) &&
						otaBytePacker::removeLEString( data, dataSize, newOffset, newOffset, scrambleBuffer ) );
				
				if( ok && (dataSize - newOffset > 0) )
				{
					ok = ok && otaBytePacker::removeNTString( data, dataSize, newOffset, newOffset, database );
					databaseSelected = true;
				}
				m_commandString = "Client attempted to switch user to " + username;
				if(databaseSelected)
					m_commandString += " and database to " + database;	
			}
			break;
					
			case OTA_CLIENT_COMMAND_STMT_PREPARE:    				// mysql_stmt_prepare
				ok = otaBytePacker::removeNTString( data, dataSize, newOffset, newOffset, m_commandString );
			break;
					
			case OTA_CLIENT_COMMAND_STMT_EXECUTE:    				// mysql_stmt_execute
			{
				unsigned int statement;
				ok = otaBytePacker::removeBasicType( data, dataSize, newOffset, newOffset, statement );
				m_commandString = "Client attempted to execute prepared statement " + statement;	
			}
			break;
					
			case OTA_CLIENT_COMMAND_STMT_CLOSE:      				// mysql_stmt_close
			{
				unsigned int statement;
				ok = otaBytePacker::removeBasicType( data, dataSize, newOffset, newOffset, statement );
				m_commandString = "Client attempted to close prepared statement " + statement;	
			}
			break;
					
			case OTA_CLIENT_COMMAND_STMT_RESET:      				// mysql_stmt_reset
			{
				unsigned int statement;
				ok = otaBytePacker::removeBasicType( data, dataSize, newOffset, newOffset, statement );
				m_commandString = "Client attempted to reset prepared statement " + statement;	
			}
			break;
				
			default:
				m_commandType = OTA_CLIENT_COMMAND_IRRELEVANT;
		}
	}
	return ok;
	
}

void otaClientCommand::setDatabase( std::string database )
{
	m_database = database;
}

void otaClientCommand::processResponse( const otaTime arrivalTime, otaServerResponse& response )
{
	response.getResponseData( 	m_responseType, 
					m_responsePacketCount, 
    	 				m_responseByteCount, 
	  				m_autoIncrement, 
       					m_rows, 
	    				m_fields, 
	 				m_errNo, 
      					m_responseMessage);
}

unsigned char otaClientCommand::getType()
{
	return m_commandType;
}
	
std::string otaClientCommand::getCommand()
{
	return m_commandString;
}
	
std::string otaClientCommand::getDatabase()
{
	return m_database;	
}
	
std::string otaClientCommand::getResponseMessage()
{
	return m_responseMessage;
}
	
	
otaTime otaClientCommand::getStart()
{
	return m_start;
}
	
otaTime otaClientCommand::getEnd()
{
	return m_end;
}
	
unsigned int otaClientCommand::getExitCode()
{
	return m_responseType;
}
	
	
unsigned int otaClientCommand::getSentPacketCount()
{
	return m_commandPacketCount;
}
	
unsigned int otaClientCommand::getReceivedPacketCount()
{
	return m_responsePacketCount;
}
	
unsigned int otaClientCommand::getSentByteCount()
{
	return m_commandByteCount;
}
	
unsigned int otaClientCommand::getReceviedByteCount()
{
	return m_responseByteCount;
}
	
	
unsigned long otaClientCommand::getRows()
{
	return m_rows;
}
	
unsigned long otaClientCommand::getFields()
{
	return m_fields;
}
	
unsigned long otaClientCommand::getErrorNo()
{
	return m_errNo;
}

otaClientCommand::~otaClientCommand()
{
}


